package ua.lviv.franko.integration;

import ua.lviv.franko.triangulation.SaveStructures.Node;

public class FuncWithJacobian implements IFunction2D {

	protected Node			A;
	protected Node			B;
	protected Node			C;
	protected double		S2;

	protected IFunction2D	startFunc;
	protected double		Jacobian;
	protected double		ai, aj, ak;
	protected double		bi, bj, bk;
	protected double		ci, cj, ck;

	public FuncWithJacobian(Node A, Node B, Node C, IFunction2D startFunc) {
		this.A = A;
		this.B = B;
		this.C = C;
		this.startFunc = startFunc;

		ai = B.x * C.y - C.x * B.y;
		aj = C.x * A.y - A.x * C.y;
		ak = A.x * B.y - B.x * A.y;

		bi = B.y - C.y;
		bj = C.y - A.y;
		bk = A.y - B.y;

		ci = C.x - B.x;
		cj = A.x - C.x;
		ck = B.x - A.x;

		// Jacobian = ( (cj)*(bi) - (ci)*(bj) ) ;

		double a = Math.sqrt((ck) * (ck) + (bk) * (bk)); // a-b
		double b = Math.sqrt((ci) * (ci) + (bi) * (bi));
		double c = Math.sqrt((cj) * (cj) + (bj) * (bj));
		double p = (a + b + c) / 2.0;
		S2 = Math.sqrt(p * (p - a) * (p - b) * (p - c)) * 2;
		Jacobian = S2;

	}

	public double calculate(double x, double y) {
		// double li = Li(x, y),
		// lj = Lj(x, y),
		// lk = Lk(x, y);
		double li = x, lj = y, lk = 1 - x - y;

		x = li * A.x + lj * B.x + lk * C.x;
		y = li * A.y + lj * B.y + lk * C.y;
		return startFunc.calculate(x, y) * Jacobian;

	}

	public double calculateDerivatyX(double x, double y) {
		double li = Li(x, y), lj = Lj(x, y), lk = Lk(x, y);
		x = li * A.x + lj * B.x + lk * C.x;
		y = li * A.y + lj * B.y + lk * C.y;
		return startFunc.calculateDerivatyX(x, y) * Jacobian;
	}

	public double calculateDerivatyY(double x, double y) {
		double li = Li(x, y), lj = Lj(x, y), lk = Lk(x, y);
		x = li * A.x + lj * B.x + lk * C.x;
		y = li * A.y + lj * B.y + lk * C.y;
		return startFunc.calculateDerivatyY(x, y) * Jacobian;
	}

	public double[] convert(double x, double y) {
		double li = Li(x, y), lj = Lj(x, y), lk = Lk(x, y);
		return new double[] { li * A.x + lj * B.x + lk * C.x, y = li * A.y + lj * B.y + lk * C.y };
	}

	private double Li(double x, double y) {
		return (ai + bi * x + ci * y) / S2;
	}

	private double Lj(double x, double y) {
		return (aj + bj * x + cj * y) / S2;
	}

	private double Lk(double x, double y) {
		return (aj + bj * x + cj * y) / S2;
	}

}